package com.fjwt.gz.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fjwt.gz.core.cache.RedisUtil;
import com.fjwt.gz.core.constants.CS;
import com.fjwt.gz.core.constants.Constants;
import com.fjwt.gz.core.exception.BizException;
import com.fjwt.gz.db.dto.BlacklistExtraFieldDTO;
import com.fjwt.gz.db.dto.BlacklistRuleDTO;
import com.fjwt.gz.db.entity.*;
import com.fjwt.gz.db.vo.BlacklistRuleVO;
import com.fjwt.gz.db.vo.BlacklistVO;
import com.fjwt.gz.db.vo.DynamicHeaderVO;
import com.fjwt.gz.db.vo.FansAgentVO;
import com.fjwt.gz.service.mapper.BlacklistRuleMapper;
import com.fjwt.gz.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 黑名单规则表 服务实现类
 * </p>
 *
 * @author wangjie
 * @since 2025-05-12
 */
@Slf4j
@Service
public class BlacklistRuleService extends ServiceImpl<BlacklistRuleMapper, BlacklistRuleEntity> {


    @Autowired
    private BlacklistService blacklistService;

    @Autowired
    private ActivityBlacklistService activityBlacklistService;

    @Autowired
    private ExchangeBlacklistService exchangeBlacklistService;

    @Autowired
    private AgentInfoService agentInfoService;

    @Autowired
    private FansAgentService fansAgentService;

    @Autowired
    private FansAuthService fansAuthService;

    private static final int MAX_EXTRA_FIELDS = 4;
    private static final String CHECK_FIELD = "checkField";
    private static final String EXTRA_FIELD_PREFIX = "extraField";
    private static final String FILED_NAME_KEY = "fieldName";
    private static final String OPERATION_KEY = "operation";
    private static final String OPERATION_TITLE = "操作";
    private static final String ALIGN_CENTER = "center";
    private static final int EXTRA_FIELD_COUNT = 4;

    private static final String NAME_KEY = "name";
    private static final String AGENT_NO_KEY = "agentNo";
    private static final String NAME_TITLE = "姓名";
    private static final String AGENT_NO_TITLE = "归属机构";
    private static final String PHONE_TITLE = "手机号码";
    private static final String PHONE = "phone";


    /**
     * 黑名单规则表列表
     *
     * @param iPage
     * @return
     */
    public IPage<BlacklistRuleVO> getBlacklistRuleList(IPage iPage, BlacklistRuleDTO ruleDTO) {
        if (StrUtil.isNotBlank(ruleDTO.getAgentNo())) {
            ruleDTO.setAgentNoList(agentInfoService.queryAllSubAgentNo(ruleDTO.getAgentNo()));
            ruleDTO.setAgentNo(null);
        }
        IPage<BlacklistRuleVO> ruleVOIPage = baseMapper.getBlacklistRuleList(iPage, ruleDTO);
        if (!CollUtil.isEmpty(ruleVOIPage.getRecords())) {
            ruleVOIPage.getRecords().forEach(
                    entity -> {
                        entity.setActivityState(StrUtil.isNotBlank(entity.getActivityNames()) ? 1 : 0);
                    }
            );
        }
        return ruleVOIPage;
    }

    /**
     * 获取活动黑名单规则列表
     **/
    public List<BlacklistRuleEntity> getActivityBlacRulesList(Long activityId, Long redisOutTime) {
        // 查询活动黑名单信息
        List<ActivityBlacklistEntity> activityBlacklistEntities = activityBlacklistService.getActivityBlacklistEntity(activityId, redisOutTime);
        if (CollUtil.isEmpty(activityBlacklistEntities)) {
            return new ArrayList<>();
        }

        String blacklistRuleKey= String.format("%s%s:%s", Constants.REDIS_ACTIVITY.BLACK, Constants.REDIS_ACTIVITY.ACTIVITY_BLACKLIST_RULE, activityId);

        List<BlacklistRuleEntity> activityBlacklistRules = RedisUtil.getObject(blacklistRuleKey,
                new TypeReference<List<BlacklistRuleEntity>>() {});

        if (CollUtil.isNotEmpty(activityBlacklistRules)) {
            return activityBlacklistRules;
        }
        //从数据库中查询
        List<Long> blacklistRuleIds = new ArrayList<>();
        for (ActivityBlacklistEntity entity : activityBlacklistEntities) {
            blacklistRuleIds.add(entity.getBlacklistRuleId());
        }

        // 批量查询数据库
        LambdaQueryWrapper<BlacklistRuleEntity> gw = BlacklistRuleEntity.gw();
        gw.in(BlacklistRuleEntity::getBlacklistRuleId, blacklistRuleIds);
        activityBlacklistRules = baseMapper.selectList(gw);

        RedisUtil.set(blacklistRuleKey, activityBlacklistRules, redisOutTime, TimeUnit.MILLISECONDS);

        log.info("活动对应黑名单规则：{}", activityBlacklistRules);

        return activityBlacklistRules;
    }

    /**
     * 获取积分黑名单规则列表
     **/
    public List<BlacklistRuleEntity> getScoreBlacRulesList(Long scoreExchangeId, Long redisOutTime) {
        //福分对应黑名单
        List<ExchangeBlacklistEntity> exchangeBlacklistEntities = exchangeBlacklistService.getExchangeBlacklistEntities(scoreExchangeId, redisOutTime);
        log.info("积分对应黑名单中间表数据：{}", exchangeBlacklistEntities);
        if (CollUtil.isEmpty(exchangeBlacklistEntities)) {
            return new ArrayList<>();
        }

        String blacklistRuleKey= String.format("%s%s:%s", Constants.REDIS_ACTIVITY.BLACK, Constants.REDIS_ACTIVITY.SCORE_BLACKLIST_RULE, scoreExchangeId);

        List<BlacklistRuleEntity> scoreBlacklistRules = RedisUtil.getObject(blacklistRuleKey,
                new TypeReference<List<BlacklistRuleEntity>>() {});
        log.info("查询redis中积分对应黑名单规则：{}", scoreBlacklistRules);
        if (CollUtil.isNotEmpty(scoreBlacklistRules)) {
            return scoreBlacklistRules;
        }
        //从数据库中查询
        List<Long> blacklistRuleIds = new ArrayList<>();
        for (ExchangeBlacklistEntity entity : exchangeBlacklistEntities) {
            blacklistRuleIds.add(entity.getBlacklistRuleId());
        }

        // 批量查询数据库
        LambdaQueryWrapper<BlacklistRuleEntity> gw = BlacklistRuleEntity.gw();
        gw.in(BlacklistRuleEntity::getBlacklistRuleId, blacklistRuleIds);
        scoreBlacklistRules = baseMapper.selectList(gw);

        RedisUtil.set(blacklistRuleKey, scoreBlacklistRules, redisOutTime, TimeUnit.MILLISECONDS);
        log.info("数据库中查询积分对应黑名单规则：{}", scoreBlacklistRules);

        return scoreBlacklistRules;
    }

    /**
     * 新增黑名单规则
     *
     * @param ruleDTO
     */
    public void addBlacklistRule(BlacklistRuleDTO ruleDTO) {
        log.info("新增黑名单规则,传参：{}", JSON.toJSONString(ruleDTO));
        //参数校验
        validateRuleDTO(ruleDTO, false);
        
        BlacklistRuleEntity entity = new BlacklistRuleEntity();
        BeanUtils.copyProperties(ruleDTO, entity);

        //额外字段处理
        processExtraFields(ruleDTO.getExtraFieldList(), entity);
        
        save(entity);
    }

    /**
     * 修改黑名单规则
     * @param ruleDTO
     */
    public void updateBlacklistRule(BlacklistRuleDTO ruleDTO) {
        log.info("修改黑名单规则,传参：{}", JSON.toJSONString(ruleDTO));
        //参数校验
        validateRuleDTO(ruleDTO, true);
        //如果已经绑定了活动或者积分则不能修改
        List<ActivityBlacklistEntity> activityBlacklistEntityList = activityBlacklistService.list(ActivityBlacklistEntity.gw()
                .eq(ActivityBlacklistEntity::getBlacklistRuleId, ruleDTO.getBlacklistRuleId()));
        if (CollUtil.isNotEmpty(activityBlacklistEntityList)) {
            throw new BizException("该黑名单规则已配置活动，不能修改");
        }
        List<ExchangeBlacklistEntity> exchangeBlacklistEntityList = exchangeBlacklistService.list(ExchangeBlacklistEntity.gw()
                .eq(ExchangeBlacklistEntity::getBlacklistRuleId, ruleDTO.getBlacklistRuleId()));
        if (CollUtil.isNotEmpty(exchangeBlacklistEntityList)) {
            throw new BizException("该黑名单规则已配置福分商城，不能修改");
        }

        BlacklistRuleEntity entity = new BlacklistRuleEntity();
        BeanUtils.copyProperties(ruleDTO, entity);

        //额外字段处理
        processExtraFields(ruleDTO.getExtraFieldList(), entity);
        
        updateById(entity);
    }
    
    // 参数校验公共方法
    private void validateRuleDTO(BlacklistRuleDTO ruleDTO, boolean isUpdate) {
        if (ruleDTO == null) {
            throw new BizException("参数对象不能为空");
        }
        
        if (StrUtil.isBlank(ruleDTO.getRuleName()) || 
            StrUtil.isBlank(ruleDTO.getAgentNo()) ||
            ruleDTO.getRuleType() == null || 
            StrUtil.isBlank(ruleDTO.getRuleTip())) {
            throw new BizException("参数信息有误");
        }
        
        if (ruleDTO.getRuleType() == 1 && StrUtil.isBlank(ruleDTO.getCheckField())) {
            throw new BizException("必填校验字段不能为空");
        }
        
        if (isUpdate && ruleDTO.getBlacklistRuleId() == null) {
            throw new BizException("参数信息有误");
        }

        String agentNo = ruleDTO.getAgentNo();
        AgentInfoEntity agentInfo = agentInfoService.getAgentInfo(agentNo);
        if (agentInfo == null || agentInfo.getState() != CS.YES) {
            throw new BizException("机构不存在或已停用");
        }
        ruleDTO.setAgentNo1(agentInfo.getAgentNo1());
        ruleDTO.setAgentNo2(agentInfo.getAgentNo2());
        ruleDTO.setAgentNo3(agentInfo.getAgentNo3());
        ruleDTO.setAgentNo4(agentInfo.getAgentNo4());
    }
    
    // 额外字段处理
    private void processExtraFields(List<BlacklistExtraFieldDTO> extraFieldList, BlacklistRuleEntity entity) {
        if (CollUtil.isEmpty(extraFieldList)) {
            return;
        }
        
        int limit = Math.min(extraFieldList.size(), MAX_EXTRA_FIELDS);
        for (int i = 0; i < limit; i++) {
            try {
                String json = JSONObject.toJSONString(extraFieldList.get(i));
                switch (i) {
                    case 0: entity.setExtraField1(json); break;
                    case 1: entity.setExtraField2(json); break;
                    case 2: entity.setExtraField3(json); break;
                    case 3: entity.setExtraField4(json); break;
                }
            } catch (Exception e) {
                log.error("额外字段[{}]序列化失败", i, e);
                throw new BizException("额外字段处理异常");
            }
        }
        
        if (extraFieldList.size() > MAX_EXTRA_FIELDS) {
            log.warn("额外字段数量超过限制（{}个），仅保留前{}", MAX_EXTRA_FIELDS, MAX_EXTRA_FIELDS);
        }
    }

    /**
     * 删除黑名单规则
     *
     * @param blacklistRuleId 黑名单规则id
     */
    public void deleteBlacklistRuleById(Long blacklistRuleId) {
        if (blacklistRuleId == null) {
            throw new BizException("参数信息有误");
        }
        //判断是否存在黑名单列表
        List<BlacklistEntity> list = blacklistService.list(BlacklistEntity.gw()
                .eq(BlacklistEntity::getBlacklistRuleId, blacklistRuleId));
        if (!list.isEmpty()) {
            throw new BizException("该规则下存在黑名单列表，请先删除黑名单列表");
        }
        //判断是否已配置活动
        List<ActivityBlacklistEntity> activityBlacklistEntityList = activityBlacklistService.list(ActivityBlacklistEntity.gw()
                .eq(ActivityBlacklistEntity::getBlacklistRuleId, blacklistRuleId));
        if (!activityBlacklistEntityList.isEmpty()) {
            throw new BizException("该规则已配置活动，无法删除");
        }
        List<ExchangeBlacklistEntity> exchangeBlacklistEntityList = exchangeBlacklistService.list(ExchangeBlacklistEntity.gw()
                .eq(ExchangeBlacklistEntity::getBlacklistRuleId, blacklistRuleId));
        if (!exchangeBlacklistEntityList.isEmpty()) {
            throw new BizException("该规则已配置福分兑换，无法删除");
        }
        //删除规则表数据
        removeById(blacklistRuleId);
    }

    /**
     * 获取黑名单规则详情
     *
     * @param blacklistRuleId 黑名单规则id
     * @return 黑名单规则详情
     */
    public BlacklistRuleVO getDetailsById(Long blacklistRuleId) {
        BlacklistRuleEntity ruleEntity = getById(blacklistRuleId);
        if (ruleEntity == null) {
            throw new BizException("无当前黑名单规则");
        }
        BlacklistRuleVO ruleVO = new BlacklistRuleVO();
        BeanUtils.copyProperties(ruleEntity, ruleVO);
        
        List<BlacklistExtraFieldDTO> extraFieldList = new ArrayList<>();
        String[] extraFields = {
            ruleEntity.getExtraField1(),
            ruleEntity.getExtraField2(),
            ruleEntity.getExtraField3(),
            ruleEntity.getExtraField4()
        };
        
        for (String field : extraFields) {
            if (StrUtil.isNotBlank(field)) {
                extraFieldList.add(JSON.parseObject(field, BlacklistExtraFieldDTO.class));
            }
        }
        
        ruleVO.setExtraFieldList(extraFieldList);
        return ruleVO;
    }

    /**
     * 获取所有黑名单规则列表
     *
     * @return 黑名单规则列表
     */
    public List<BlacklistRuleVO> getAllRuleList(String agentNo) {
        List<BlacklistRuleVO> result = baseMapper.getAllRuleList(agentNo);
        if (CollUtil.isEmpty(result)) {
            return result;
        }
        for (BlacklistRuleVO blacklistRuleVO : result) {
            if (blacklistRuleVO.getRuleType() == Constants.BLACKLIST_RULE_TYPE.EMPLOYEE) {
                //固定字段内容
                addFixedHeader(blacklistRuleVO);
                continue;
            }
            List<DynamicHeaderVO> headerList = new ArrayList<>();
            addCheckFieldHeader(headerList, blacklistRuleVO);
            for (int i = 1; i <= EXTRA_FIELD_COUNT; i++) {
                addExtraFieldHeader(blacklistRuleVO, headerList, i);
            }
            addOperationHeader(headerList);
            blacklistRuleVO.setColumnNameList(headerList);
        }
        return result;
    }

    private void addFixedHeader(BlacklistRuleVO blacklistRuleVO) {
        List<DynamicHeaderVO> headerList = new ArrayList<>();

        headerList.add(new DynamicHeaderVO()
                .setKey(PHONE).setTitle(PHONE_TITLE).setDataIndex(PHONE));
        headerList.add(new DynamicHeaderVO()
                .setKey(NAME_KEY).setTitle(NAME_TITLE).setDataIndex(NAME_KEY));
        headerList.add(new DynamicHeaderVO()
                .setKey(AGENT_NO_KEY).setTitle(AGENT_NO_TITLE).setDataIndex(AGENT_NO_KEY));
    
//        addOperationHeader(headerList);
        blacklistRuleVO.setColumnNameList(headerList);
    }

    /**
     * 添加操作列
     *
     * @param headerList 表头列表
     */
    private void addOperationHeader(List<DynamicHeaderVO> headerList) {
        DynamicHeaderVO headerVO = new DynamicHeaderVO();
        headerVO.setKey(OPERATION_KEY);
        headerVO.setTitle(OPERATION_TITLE);
        headerVO.setDataIndex(OPERATION_KEY);
        headerVO.setAlign(ALIGN_CENTER);
        headerList.add(headerVO);
    }
    
    private void addCheckFieldHeader(List<DynamicHeaderVO> headerList, BlacklistRuleVO ruleVO) {
        DynamicHeaderVO headerVO = new DynamicHeaderVO();
        String checkField = ruleVO.getCheckField();
        headerVO.setKey(CHECK_FIELD);
        headerVO.setTitle("phone".equals(checkField) ? "手机号" : "实名唯一ID");
        headerVO.setDataIndex(CHECK_FIELD);
        headerList.add(headerVO);
    }
    
    private void addExtraFieldHeader(BlacklistRuleVO ruleVO, List<DynamicHeaderVO> headerList, int fieldIndex) {
        String extraField = null;
        switch (fieldIndex) {
            case 1: extraField = ruleVO.getExtraField1(); break;
            case 2: extraField = ruleVO.getExtraField2(); break;
            case 3: extraField = ruleVO.getExtraField3(); break;
            case 4: extraField = ruleVO.getExtraField4(); break;
            default: return;
        }
        if (StrUtil.isNotBlank(extraField)) {
            DynamicHeaderVO headerVO = new DynamicHeaderVO();
            headerVO.setKey(EXTRA_FIELD_PREFIX + fieldIndex);
            headerVO.setDataIndex(EXTRA_FIELD_PREFIX + fieldIndex);
            try {
                JSONObject jsonObject = JSON.parseObject(extraField);
                String title = jsonObject.containsKey(FILED_NAME_KEY) 
                    ? jsonObject.getString(FILED_NAME_KEY) 
                    : "未知字段";
                headerVO.setTitle(title);
            } catch (Exception e) {
                log.error("解析黑名单规则字段信息异常", e);
            }
            headerList.add(headerVO);
        }
    }

    /**
     * 根据机构号获取黑名单规则列表
     *
     * @return 黑名单规则列表
     */
    public List<BlacklistRuleVO> getListByAgentNo(String agentNo) {
        AgentInfoEntity agentInfo = agentInfoService.getAgentInfo(agentNo);
        if (agentInfo == null) {
            return new ArrayList<>();
        }
        return baseMapper.getBlacklistRuleByAgentNo(agentInfo);
    }

    /**
     * 黑名单规则校验
     * @param blacklistRuleEntities 黑名单规则列表
     * @param fansEntity 用户基本信息
     * @param typeId 活动id/积分id
     * @param type 类型 0 活动 1 积分
     * @param redisOutTime redis过期时间
     */
    public void commonBlacklistRuleValid(List<BlacklistRuleEntity> blacklistRuleEntities, FansEntity fansEntity, Long typeId, Integer type, Long redisOutTime, String appId) {
        if (CollUtil.isEmpty(blacklistRuleEntities)) {
            return;
        }
        String title = type == 0 ? "活动" : "积分";
        //查询绑定的机构员工编号
        FansAgentVO fansAgentVO = fansAgentService.selectEmployeeByFansId(fansEntity.getFansId(), appId);
        log.info("当前用户绑定的机构员工编号信息:{}", fansAgentVO);
        // 查询用户实名信息
        FansAuthEntity fansAuthEntity = fansAuthService.getOne(FansAuthEntity.gw()
                .eq(FansAuthEntity::getFansId, fansEntity.getFansId())
                .eq(FansAuthEntity::getAgentNo, blacklistRuleEntities.get(0).getAgentNo()));

        // 遍历规则
        for (BlacklistRuleEntity blackListRule : blacklistRuleEntities) {
            Integer ruleType = blackListRule.getRuleType();
            //规则提示语
            String ruleTip = StrUtil.isNotBlank(blackListRule.getRuleTip()) ? blackListRule.getRuleTip() : "您因违反规则被限制参与活动";
            if (ruleType == 1) {
                // 查询用户黑名单
                Map<String, BlacklistEntity> blackListMap = blacklistService.getBlackListByRuleId(blackListRule, redisOutTime);
                if (CollUtil.isEmpty(blackListMap)) {
                    log.info("用户黑名单列表为空");
                    continue;
                }
                //校验手机号或者唯一标识
                BlacklistEntity blacklistEntity = "phone".equals(blackListRule.getCheckField()) ?
                        blackListMap.get(fansEntity.getPhone()) : blackListMap.get(fansAuthEntity.getCstmNo());

                if (ObjectUtils.isNotEmpty(blacklistEntity)) {
                    log.warn("用户在黑名单内（{}ID：{}，规则ID：{}），用户信息：{}", title, typeId, blackListRule.getBlacklistRuleId(), JsonUtils.toJson(blacklistEntity));
                    throw new BizException(ruleTip);
                }
            } else {
                // 查询客户经理黑名单
                Map<String, BlacklistVO> cmBlackList = blacklistService.getCMBlackList(blackListRule, redisOutTime);
                if (CollUtil.isEmpty(cmBlackList) || fansAgentVO == null) {
                    log.info("客户经理黑名单为空");
                    continue;
                }
                BlacklistVO blacklistVO = cmBlackList.get(fansAgentVO.getEmployeeNo());

                if (ObjectUtils.isNotEmpty(blacklistVO)) {
                    log.warn("用户在客户经理黑名单内（{}ID：{}，规则ID：{}），用户信息：{}", title, typeId, blackListRule.getBlacklistRuleId(), JsonUtils.toJson(blacklistVO));
                    throw new BizException(ruleTip);
                }
            }
        }
    }

    /**
     * 修改黑名单规则提示语
     *
     * @param ruleDTO 黑名单规则信息
     */
    public void updateBlacklistRuleTips(BlacklistRuleDTO ruleDTO) {
        if (ruleDTO.getBlacklistRuleId() == null) {
            throw new BizException("参数异常，请检查");
        }
        BlacklistRuleEntity entity = baseMapper.selectById(ruleDTO.getBlacklistRuleId());
        entity.setRuleTip(ruleDTO.getRuleTip());
        baseMapper.updateById(entity);
    }

    public JSONObject getConfigFields(Long blacklistRuleId) {
        if (blacklistRuleId == null) {
            throw new BizException("参数异常，请检查");
        }
        BlacklistRuleEntity ruleEntity = baseMapper.selectById(blacklistRuleId);
        if (ruleEntity == null) {
            throw new BizException("无该规则，请检查");
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(CHECK_FIELD, PHONE.equals(ruleEntity.getCheckField()) ? "手机号" : "实名唯一标识");
        String[] extraFields = {
                ruleEntity.getExtraField1(),
                ruleEntity.getExtraField2(),
                ruleEntity.getExtraField3(),
                ruleEntity.getExtraField4()
        };
        int i = 1;
        for (String field : extraFields) {
            if (StrUtil.isNotBlank(field)) {
                try {
                    BlacklistExtraFieldDTO dto = JSON.parseObject(field, BlacklistExtraFieldDTO.class);
                    jsonObject.put(CHECK_FIELD + "_" + i, dto.getFieldName());
                } catch (Exception e) {
                    log.warn("额外字段解析失败，字段内容：{}", field, e);
                }
                i++;
            }
        }
        return jsonObject;
    }
}
